#include "DoWhileBuilder.h"

#include "ScriptCompiler/AST/DoWhileNode.h"

#include "ScriptCompiler/ASTBuilder/ExpressionBuilder.h"
#include "ScriptCompiler/ASTBuilder/SentenceBlockBuilder.h"

#include "ScriptCompiler/ScriptFileContext.h"

#include "ScriptCompiler/Token/Token.h"

CDoWhileBuilder::CDoWhileBuilder(std::shared_ptr<CScriptFileContext> InContext)
{
    Context = InContext;
    Result = std::make_shared<CDoWhileNode>(InContext);
}

bool CDoWhileBuilder::ReadCurentToken()
{
    //read do 
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::Do)
        {
            Context->RaiseError(10033,Token, U"Expect 'do' here");
            return false;
        }
        Result->Do = Token;
        Context->CurrentTokenIndex++;
    }

    //make sure next token is '{'
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::LeftBrace)
        {
            Context->RaiseError(10148,Token, U"Expect '{' after 'do', do not allow loop body without '{ }'");
            return false;
        }
        //Result->LeftBrace = Token;
        Context->CurrentTokenIndex++;
    }

    //find '}'
    uint64_t RightBraceIndex;
    {
        auto RightBracePos = FindPairedBrace(Context);
        if (!RightBracePos)
        {
            //raise error, require '}'
            Context->RaiseError(10149,Context->GetCurrentToken(), U"Expected paired '}' ");
            return false;
        }
        RightBraceIndex = *RightBracePos;
    }   

    //read body
    {
        auto SentenceBlockBuilder = std::make_shared<CSentenceBlockBuilder>(Context,RightBraceIndex);
        if (!SentenceBlockBuilder->ReadCurentToken())
        {
            return false;
        }

        Result->Body = SentenceBlockBuilder->Result;

    }

    //skip '}'
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::RightBrace)
        {
            Context->RaiseError(10190,Token, U"Expect '}' here");
            return false;
        }
        Context->CurrentTokenIndex++;
    }

    //read 'while'
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::While)
        {
            Context->RaiseError(10034,Token, U"Expect 'while' here");
            return false;
        }
        //Result->While = Token;
        Context->CurrentTokenIndex++;
    }

    //read '('
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::LeftParentheses)
        {
            Context->RaiseError(10035,Token, U"Expect '(' here");
            return false;
        }
        //Result->LeftParentheses = Token;
        Context->CurrentTokenIndex++;
    }
    
    //find ')'
    uint64_t RightParenthesesIndex;
    {
        auto RightParenthesesPos = FindPairedParentheses(Context);
        if (!RightParenthesesPos)
        {
            //raise error, require ')'
            Context->RaiseError(10036,Context->GetCurrentToken(), U"Expected paired ')' ");
            return false;
        }
        RightParenthesesIndex = *RightParenthesesPos;
    }

    //read condition
    {
        auto ExpressionBuilder = std::make_shared<CExpressionBuilder>(Context,RightParenthesesIndex);
        if (!ExpressionBuilder->ReadCurentToken())
        {
            return false;
        }
        Result->Condition = ExpressionBuilder->Result;
    }

    //read ')'
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::RightParentheses)
        {
            Context->RaiseError(10037,Token, U"Expect ')' here");
            return false;
        }
        //Result->RightParentheses = Token;
        Context->CurrentTokenIndex++;
    }
    return true;

}
